import {
  DEBUG,
  API_SERVER,
  API_DEV_SERVER,
  HTTP_TIMEOUT
} from '../constants/setting'

import DB from '../utils/storage'
import { Platform, InteractionManager } from 'react-native'
import md5 from 'md5'
import { json2Form } from '../utils/func'

import {
  CALL_API,
  SHOW_LOADING,
  HIDE_LOADING,
  SHOW_TOAST,
  REQUEST_BEGIN,
  USER_LOGOUT
} from '../constants/actionType'

import cacheMap, {
  DOUBLE_CB,
  NO_CACHE,
  ONLY_CACHE
} from '../constants/cache'

import {
  toast
} from '../actions/app'

const API_ROOT = DEBUG ? API_DEV_SERVER : API_SERVER

function callApi (api, { body, ...others }) {
  let fullUrl = (api.indexOf('http') === -1) ? API_ROOT + api : api
  let options
  if (others.method === 'GET') {
    fullUrl += `?${body}`
    options = others
  } else {
    options = {
      body,
      ...others
    }
  }

  console.log('CALL_API', fullUrl, options)

  return fetch(fullUrl, options)
    .then(response => {
      let result
      console.log('请求接口状态：', response.status, response)
      if (response.status >= 200 && response.status < 300) {
        result = response.json()
        console.log('===result==', result)
      } else {
        result = response.text().then((text) => Promise.reject(text))
      }
      return result
      // return response.text().then(text => {
      //   console.log(`请求状态${response.status},结果: ${text}`)
      //   let json = null
      //   let result
      //   try {
      //     json = JSON.parse(text)
      //   } catch (e) {
      //     json = null
      //   } finally {
      //     if (!json || response.status < 200 || response.status >= 300) {
      //       result = Promise.reject(new Error(text))
      //     } else {
      //       result = Promise.resolve(json)
      //     }
      //     return result // eslint-disable-line
      //   }
      // })
    })
}

export default store => next => action => {
  if (action.type !== CALL_API) {
    // return InteractionManager.runAfterInteractions(() => next(action));
    return next(action)
  }

  const { app, props } = store.getState()

  const uuid = props.get('uuid')
  const version = props.get('version')
  const token = app.get('token')

  const {
    api,
    method = 'POST',
    body = {},
    headers = {
      Accept: 'application/json'
      // 'Content-Type': 'application/json'
    },
    loading = false,
    success,
    fail = SHOW_TOAST,
    cache = NO_CACHE,
    timeout = HTTP_TIMEOUT,
    requestOnlyWhen,
    noRepeat,
    done
  } = action.payload

  // if (token) {
  //   headers.Authorization = `Bearer ${token}`
  // }

  if (requestOnlyWhen && !requestOnlyWhen(store.getState())) {
    console.info('触发requesetOnlyWhen, 不进行网络请求')
    if (done) {
      done()
    }
    return
  }

  function actionWith (data) {
    const finalAction = Object.assign({}, action, data)
    delete finalAction[CALL_API]
    return finalAction
  }

  const clientType = Platform.OS === 'ios' ? 2 : 1
  let params
  const contentType = headers['Content-Type']
  if (contentType && contentType.includes('multipart')) {
    params = {
      clientType,
      appUuid: uuid,
      version,
      ...body
    }
  } else {
    params = {
      clientType,
      data: JSON.stringify(body),
      appUuid: uuid,
      version
    }
  }

  const randomStr = Math.random().toString(36).slice(2, 5)
  params.nonstr = randomStr
  if (token) {
    params.token = token
    const signKey = md5(`${token}${uuid}${clientType}${randomStr}`)
    params.sign = md5(`${params.data || '{}'}${signKey}`)
  }

  const form = new FormData()
  Object.keys(params).forEach(key => {
    const value = params[key]
    if (Array.isArray(value)) {
      value.forEach(item => form.append(key, item))
    } else {
      form.append(key, params[key])
    }
  })
  const options = {
    headers,
    body: method === 'GET' ? json2Form(params) : form,
    method,
    timeout
  }

  const id = md5(JSON.stringify({
    api,
    body
  }))

  DB.get(id).then(cacheData => {
    if (cacheData && cache !== NO_CACHE) {
      console.info('使用缓存数据', cacheData)
      if (typeof success === 'string') {
        InteractionManager.runAfterInteractions(() => next(actionWith({
          response: cacheData.response,
          type: success
        })))
      } else {
        InteractionManager.runAfterInteractions(() => success(cacheData.response))
      }

      if (cache === ONLY_CACHE && (new Date().getTime() - cacheData.updateAt) < cacheMap.get(api)) {
        return
      }
    }

    if (loading && !cacheData) {
      InteractionManager.runAfterInteractions(() => {
        next(actionWith({ type: SHOW_LOADING }))
      })
    }

    const timestamp = new Date().getTime()

    if (noRepeat) {
      const { net } = store.getState()
      const lastRequest = net.get('lastRequest')
      if (lastRequest.get('id') === id && timestamp - lastRequest.get('timestamp') < 2000) {
        return InteractionManager.runAfterInteractions(
          () => store.dispatch(toast('error', '请不要重复提交'))
        )
      }
    }

    next(actionWith({
      type: REQUEST_BEGIN,
      payload: {
        id,
        timestamp
      }
    }))

    callApi(api, options).then(
      response => {
        console.log(`接口返回数据——code:${response.code}, msg:${response.msg}`)
        // todo: 检查json,code为成功才存
        if (response.code !== '0000') {
          return Promise.reject({ // eslint-disable-line
            message: response.msg,
            code: response.code
          })
        }
        if (cache !== NO_CACHE) {
          DB.put(id, {
            response,
            updateAt: new Date().getTime()
          })
        }

        if (!cacheData || cache === DOUBLE_CB || cache === NO_CACHE) {
          if (typeof success === 'string') {
            InteractionManager.runAfterInteractions(() => next(actionWith({
              response,
              type: success
            })))
          } else {
            InteractionManager.runAfterInteractions(() => success(response))
          }
        }
      })
      .catch(error => {
        console.warn('请求网络出错', error.message)
        if (error.message.includes('请重新登录')) {
          next(actionWith({ type: USER_LOGOUT }))
        }
        const msg = error.message || '请求出错'
        if (fail === SHOW_TOAST) {
          InteractionManager.runAfterInteractions(() => store.dispatch(toast('error', msg)))
        } else if (typeof fail === 'string') {
          InteractionManager.runAfterInteractions(() => next(actionWith({
            type: fail,
            error
          })))
        } else {
          InteractionManager.runAfterInteractions(() => fail(error))
        }
      })
      .finally(() => {
        if (done) {
          InteractionManager.runAfterInteractions(done)
        }

        if (loading && !cacheData) {
          InteractionManager.runAfterInteractions(() => {
            next(actionWith({ type: HIDE_LOADING }))
          })
        }
      })
  })
}
